package com.dbms.execution.execution;

import com.dbms.catalog.Catalog;
import com.dbms.common.RID;
import com.dbms.common.Schema;
import com.dbms.common.Tuple;
import com.dbms.execution.plan.PlanNode;
import com.dbms.storage.BufferPoolManager;
import com.dbms.storage.Page;
import com.dbms.storage.TablePage;

import java.io.IOException;

/**
 * DropUserExecutor (删除用户执行器) 负责执行删除用户的计划。
 * 这个执行器通过手动扫描系统表 `_users_` 来查找并删除指定的用户记录。
 * 这么做是因为用户表的主键（用户名）是字符串，可能没有直接的索引支持，
 * 或者为了简化系统表的操作而采用顺序扫描。
 */
public class DropUserExecutor implements Executor {

    /**
     * 目录管理器，用于获取 `_users_` 表的元数据。
     */
    private final Catalog catalog;

    /**
     * 缓冲池管理器，用于访问和修改包含用户数据的页面。
     */
    private final BufferPoolManager bufferPoolManager;

    /**
     * 要删除的用户名。
     */
    private final String usernameToDelete;

    /**
     * 标志位，确保删除操作只执行一次。
     */
    private boolean hasExecuted = false;

    /**
     * 构造函数。
     * @param catalog 目录管理器
     * @param bufferPoolManager 缓冲池管理器
     * @param usernameToDelete 要删除的用户名
     */
    public DropUserExecutor(Catalog catalog, BufferPoolManager bufferPoolManager, String usernameToDelete) {
        this.catalog = catalog;
        this.bufferPoolManager = bufferPoolManager;
        this.usernameToDelete = usernameToDelete;
    }

    /**
     * 打开执行器，重置执行状态。
     */
    @Override
    public void open() {
        hasExecuted = false;
    }

    /**
     * 执行删除用户的逻辑。
     * @return 总是返回 null，因为 DDL/DCL 操作不产生输出元组。
     */
    @Override
    public Tuple next() {
        if (hasExecuted) {
            return null;
        }

        // 1. 从目录中获取 `_users_` 表的元数据
        Catalog.TableMetadata userInfo = catalog.getTable("_users_");
        if (userInfo == null) {
            throw new RuntimeException("System error: _users_ table not found.");
        }

        // 2. 从表的根页面开始，遍历所有页面
        int currentPageId = userInfo.rootPageId;
        Page currentPage = null;
        boolean userFoundAndDeleted = false;

        try {
            // 遍历由页面组成的链表，直到找到并删除用户或遍历完所有页面
            while (currentPageId != TablePage.INVALID_PAGE_ID && !userFoundAndDeleted) {
                // 从缓冲池获取当前页面
                currentPage = bufferPoolManager.fetchPage(currentPageId);
                if (currentPage == null) break;

                // 因为我们要执行删除操作，所以需要对页面加写锁
                currentPage.wLock();

                try {
                    TablePage tablePage = new TablePage(currentPage);
                    // 遍历页面中的所有槽位
                    for (int slotNum = 0; slotNum < tablePage.getSlotCount(); slotNum++) {
                        byte[] tupleData = tablePage.getTuple(slotNum);
                        if (tupleData == null) continue; // 跳过已删除或无效的槽位

                        // 反序列化元组数据以读取内容
                        Tuple tuple = new Tuple(tupleData, userInfo.schema);
                        String username = (String) tuple.getValue(0); // 假设 user_name 是第一列

                        // 检查用户名是否匹配
                        if (username.equals(usernameToDelete)) {
                            // 找到了！执行删除操作
                            tablePage.deleteTuple(slotNum);
                            userFoundAndDeleted = true;
                            break; // 假设用户名是唯一的，找到后就可以停止当前页面的扫描
                        }
                    }
                } finally {
                    // 3. 释放写锁，并将页面解钉
                    currentPage.wUnlock();
                    // 如果我们在这个页面上执行了删除，页面就是脏的 (dirty=true)，需要写回磁盘
                    bufferPoolManager.unpinPage(currentPageId, userFoundAndDeleted);
                }

                // 如果还没找到用户，则移动到下一个页面
                if (!userFoundAndDeleted) {
                    currentPageId = new TablePage(currentPage).getNextPageId();
                }
            }
        } catch (IOException e) {
            throw new RuntimeException("Failed to drop user", e);
        } finally {
            hasExecuted = true; // 标记为已执行，无论成功与否
        }

        // 如果遍历完所有页面后仍未找到用户，则打印警告信息
        if (!userFoundAndDeleted) {
            System.out.println("Warning: User '" + usernameToDelete + "' not found. Nothing to drop.");
        }

        return null;
    }

    @Override
    public void close() {}

    @Override
    public Schema getSchema() {
        return null;
    }

    @Override
    public PlanNode getPlanNode() {
        return null;
    }
}